home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / shells / tcshsrc.zoo / tcsh / sh.dir.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-16  |  27.1 KB  |  1,192 lines

  1. /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/sh.dir.c,v 3.3 1991/07/31 07:12:20 christos Exp $ */
  2. /*
  3.  * sh.dir.c: Directory manipulation functions
  4.  */
  5. /*-
  6.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *    This product includes software developed by the University of
  20.  *    California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37. #include "config.h"
  38. RCSID("$Id: sh.dir.c,v 3.3 1991/07/31 07:12:20 christos Exp $")
  39.  
  40.  
  41. #include "sh.h"
  42. #ifdef __MINT__
  43. extern Char *Lastslash();
  44. #endif
  45.  
  46. /*
  47.  * C Shell - directory management
  48.  */
  49.  
  50. static    struct directory    *dfind        __P((Char *));
  51. static    Char             *dfollow    __P((Char *));
  52. static    void                printdirs    __P((void));
  53. static    Char             *dgoto        __P((Char *));
  54. static    void                dnewcwd    __P((struct directory *));
  55. static    void                dset        __P((Char *));
  56.  
  57. struct directory dhead;        /* "head" of loop */
  58. int     printd;            /* force name to be printed */
  59.  
  60. #ifdef CSHDIRS
  61. int     bequiet = 0;        /* do not print dir stack -strike */
  62.  
  63. #endif
  64. static int dirflag = 0;
  65.  
  66. /*
  67.  * dinit - initialize current working directory
  68.  */
  69. void
  70. dinit(hp)
  71.     Char   *hp;
  72. {
  73.     register char *tcp;
  74.     register Char *cp;
  75.     register struct directory *dp;
  76.     char    path[MAXPATHLEN];
  77.     static char *emsg = "tcsh: Trying to start from \"%s\"\n";
  78.  
  79.     /* Don't believe the login shell home, because it may be a symlink */
  80.     tcp = getwd(path);        /* see ngetwd.c for System V version */
  81.     if (tcp == NULL || *tcp == '\0') {
  82.     (void) xprintf("tcsh: %s\n", path);
  83.     if (hp && *hp) {
  84.         tcp = short2str(hp);
  85.         (void) xprintf(emsg, tcp);
  86.         if (chdir(tcp) == -1)
  87.         cp = NULL;
  88.         else
  89.         cp = hp;
  90.     }
  91.     else
  92.         cp = NULL;
  93.     if (cp == NULL) {
  94.         (void) xprintf(emsg, "/");
  95.         if (chdir("/") == -1)
  96.         /* I am not even try to print an error message! */
  97.         xexit(1);
  98.         cp = SAVE("/");
  99.     }
  100.     }
  101.     else {
  102. #ifdef S_IFLNK
  103.     struct stat swd, shp;
  104.  
  105.     /*
  106.      * See if $HOME is the working directory we got and use that
  107.      */
  108.     if (hp && *hp &&
  109.         stat(tcp, &swd) != -1 && stat(short2str(hp), &shp) != -1 &&
  110.         swd.st_dev == shp.st_dev && swd.st_ino == shp.st_ino)
  111.         cp = hp;
  112.     else {
  113.         char   *cwd;
  114.  
  115.         /*
  116.          * use PWD if we have it (for subshells)
  117.          */
  118.         if (cwd = getenv("PWD")) {
  119.         if (stat(cwd, &shp) != -1 && swd.st_dev == shp.st_dev &&
  120.             swd.st_ino == shp.st_ino)
  121.             tcp = cwd;
  122.         }
  123.         cp = dcanon(str2short(tcp), STRNULL);
  124.     }
  125. #else                /* S_IFLNK */
  126.     cp = dcanon(str2short(tcp), STRNULL);
  127. #endif                /* S_IFLNK */
  128.     }
  129.  
  130.     dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
  131.     dp->di_name = Strsave(cp);
  132.     dp->di_count = 0;
  133.     dhead.di_next = dhead.di_prev = dp;
  134.     dp->di_next = dp->di_prev = &dhead;
  135.     printd = 0;
  136.     dnewcwd(dp);
  137. }
  138.  
  139. static void
  140. dset(dp)
  141. Char *dp;
  142. {
  143.     /*
  144.      * Don't call set() directly cause if the directory contains ` or
  145.      * other junk characters glob will fail. 
  146.      */
  147.     register Char **vec = (Char **) xmalloc((size_t) (2 * sizeof(Char **)));
  148.  
  149.     vec[0] = Strsave(dp);
  150.     vec[1] = 0;
  151.     setq(STRcwd, vec, &shvhed);
  152.     Setenv(STRPWD, dp);
  153. }
  154.  
  155. #define DIR_LONG 1
  156. #define DIR_VERT 2
  157. #define DIR_LINE 4
  158.  
  159. static void
  160. skipargs(v, str)
  161.     Char ***v;
  162.     char   *str;
  163. {
  164.     Char  **n = *v, *s;
  165.  
  166.     dirflag = 0;
  167.     for (n++; *n != NOSTR && (*n)[0] == '-'; n++)
  168.     for (s = &((*n)[1]); *s; s++)
  169.         switch (*s) {
  170.         case 'l':
  171.         dirflag |= DIR_LONG;
  172.         break;
  173.         case 'v':
  174.         dirflag |= DIR_VERT;
  175.         break;
  176.         case 'n':
  177.         dirflag |= DIR_LINE;
  178.         break;
  179.         default:
  180.         stderror(ERR_DIRUS, short2str(**v), str);
  181.         break;
  182.         }
  183.     *v = n;
  184. }
  185.  
  186. /*
  187.  * dodirs - list all directories in directory loop
  188.  */
  189. /*ARGSUSED*/
  190. void
  191. dodirs(v, c)
  192.     Char  **v;
  193.     struct command *c;
  194. {
  195.     skipargs(&v, "");
  196.  
  197.     if (*v != NOSTR)
  198.     stderror(ERR_DIRUS, "dirs", "");
  199.     printdirs();
  200. }
  201.  
  202. static void
  203. printdirs()
  204. {
  205.     register struct directory *dp;
  206.     Char   *s, *hp = value(STRhome);
  207.     int     idx, len, cur;
  208.     extern int T_Cols;
  209.  
  210.     if (*hp == '\0')
  211.     hp = NOSTR;
  212.     dp = dcwd;
  213.     idx = 0;
  214.     cur = 0;
  215.     do {
  216.     if (dp == &dhead)
  217.         continue;
  218.     if (dirflag & DIR_VERT) {
  219.         xprintf("%d\t", idx++);
  220.         cur = 0;
  221.     }
  222.     if (!(dirflag & DIR_LONG) && hp != NOSTR && !eq(hp, STRslash) &&
  223.         prefix(hp, dp->di_name))
  224.         len = Strlen(s = (dp->di_name + Strlen(hp))) + 2;
  225.     else
  226.         len = Strlen(s = dp->di_name) + 1;
  227.  
  228.     cur += len;
  229.     if ((dirflag & DIR_LINE) && cur >= T_Cols - 1 && len < T_Cols) {
  230.         xprintf("\n");
  231.         cur = len;
  232.     }
  233.     xprintf(s != dp->di_name ? "~%s%c" : "%s%c",
  234.         short2str(s), (dirflag & DIR_VERT) ? '\n' : ' ');
  235.     } while ((dp = dp->di_prev) != dcwd);
  236.     if (!(dirflag & DIR_VERT))
  237.     xprintf("\n");
  238. }
  239.  
  240. void
  241. dtildepr(home, dir)
  242.     register Char *home, *dir;
  243. {
  244.  
  245.     if (!eq(home, STRslash) && prefix(home, dir))
  246.     xprintf("~%s", short2str(dir + Strlen(home)));
  247.     else
  248.     xprintf("%s", short2str(dir));
  249. }
  250.  
  251. void
  252. dtilde()
  253. {
  254.     struct directory *d = dcwd;
  255.  
  256.     do {
  257.     if (d == &dhead)
  258.         continue;
  259.     d->di_name = dcanon(d->di_name, STRNULL);
  260.     } while ((d = d->di_prev) != dcwd);
  261.  
  262.     dset(dcwd->di_name);
  263. }
  264.  
  265.  
  266. /* dnormalize():
  267.  *    If the name starts with . or .. then we might need to normalize
  268.  *    it depending on the symbolic link flags
  269.  */
  270. Char   *
  271. dnormalize(cp)
  272.     Char   *cp;
  273. {
  274.  
  275. #define TRM(a) ((a) & TRIM)
  276. #define ISDOT(c) (TRM((c)[0]) == '.' && ((TRM((c)[1]) == '\0') || \
  277.           (TRM((c)[1]) == '/')))
  278. #define ISDOTDOT(c) (TRM((c)[0]) == '.' && ISDOT(&((c)[1])))
  279.  
  280.     if (TRM(cp[0]) == '/')
  281.     return (Strsave(cp));
  282.  
  283. #ifdef S_IFLNK
  284.     if (adrof(STRignore_symlinks)) {
  285.     int     dotdot = 0;
  286.     Char   *dp, *cwd;
  287. #ifdef apollo
  288.     bool slashslash;
  289. #endif
  290.  
  291.     cwd = (Char *) xmalloc((size_t) ((Strlen(dcwd->di_name) + 3) *
  292.                      sizeof(Char)));
  293.     (void) Strcpy(cwd, dcwd->di_name);
  294. #ifdef apollo
  295.     slashslash = cwd[0] == '/' && cwd[1] == '/';
  296. #endif
  297.  
  298.     /*
  299.      * Ignore . and count ..'s
  300.      */
  301.     while (*cp) {
  302.         if (ISDOT(cp)) {
  303.         if (*++cp)
  304.             cp++;
  305.         }
  306.         else if (ISDOTDOT(cp)) {
  307.         dotdot++;
  308.         cp += 2;
  309.         if (*cp)
  310.             cp++;
  311.         }
  312.         else
  313.         break;
  314.     }
  315.     while (dotdot > 0) 
  316.         if ((dp = Strrchr(cwd, '/'))) {
  317. #ifdef apollo
  318.         if (dp == &cwd[1]) 
  319.             slashslash = 1;
  320. #endif
  321.         *dp = '\0';
  322.         dotdot--;
  323.         }
  324.         else
  325.         break;
  326.  
  327.     if (*cp) {
  328.         if ((TRM(cwd[(dotdot = Strlen(cwd)) - 1])) != '/')
  329.         cwd[dotdot++] = '/';
  330.         cwd[dotdot] = '\0';
  331.         dp = Strspl(cwd, cp);
  332.         xfree((ptr_t) cwd);
  333.         return dp;
  334.     }
  335.     else {
  336.         if (!*cwd) {
  337.         cwd[0] = '/';
  338. #ifdef apollo
  339.         cwd[1] = '/';
  340.         cwd[2] = '\0';
  341. #else
  342.         cwd[1] = '\0';
  343. #endif
  344.         }
  345. #ifdef apollo
  346.         else if (slashslash && cwd[1] == '\0') {
  347.         cwd[1] = '/';
  348.         cwd[2] = '\0';
  349.         }
  350. #endif
  351.         return cwd;
  352.     }
  353.     }
  354. #endif
  355.     return Strsave(cp);
  356. }
  357.  
  358. /*
  359.  * dochngd - implement chdir command.
  360.  */
  361. /*ARGSUSED*/
  362. void
  363. dochngd(v, c)
  364.     Char  **v;
  365.     struct command *c;
  366. {
  367.     register Char *cp;
  368.     register struct directory *dp;
  369.  
  370.     skipargs(&v, " [<dir>]");
  371.     printd = 0;
  372.     if (*v == NOSTR) {
  373.     if ((cp = value(STRhome)) == NOSTR || *cp == 0)
  374.         stderror(ERR_NAME | ERR_NOHOMEDIR);
  375.     if (chdir(short2str(cp)) < 0)
  376.         stderror(ERR_NAME | ERR_CANTCHANGE);
  377.     cp = Strsave(cp);
  378.     }
  379.     else if (v[1] != NOSTR) {
  380.     stderror(ERR_NAME | ERR_TOOMANY);
  381.     /* NOTREACHED */
  382.     return;
  383.     }
  384.     else if ((dp = dfind(*v)) != 0) {
  385.     char   *tmp;
  386.  
  387.     printd = 1;
  388.     if (chdir(tmp = short2str(dp->di_name)) < 0)
  389.         stderror(ERR_SYSTEM, tmp, strerror(errno));
  390.     dcwd->di_prev->di_next = dcwd->di_next;
  391.     dcwd->di_next->di_prev = dcwd->di_prev;
  392.     dfree(dcwd);
  393.     dnewcwd(dp);
  394.     return;
  395.     }
  396.     else
  397.     cp = dfollow(*v);
  398.     dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
  399.     dp->di_name = cp;
  400.     dp->di_count = 0;
  401.     dp->di_next = dcwd->di_next;
  402.     dp->di_prev = dcwd->di_prev;
  403.     dp->di_prev->di_next = dp;
  404.     dp->di_next->di_prev = dp;
  405.     dfree(dcwd);
  406.     dnewcwd(dp);
  407. }
  408.  
  409. static Char *
  410. dgoto(cp)
  411.     Char   *cp;
  412. {
  413.     Char   *dp;
  414.  
  415. #ifdef __MINT__
  416.     if (!is_abspath(cp)) {
  417. #else
  418.     if (*cp != '/') {
  419. #endif
  420.     register Char *p, *q;
  421.     int     cwdlen;
  422.  
  423.     for (p = dcwd->di_name; *p++;);
  424.     if ((cwdlen = p - dcwd->di_name - 1) == 1)    /* root */
  425.         cwdlen = 0;
  426.     for (p = cp; *p++;);
  427.     dp = (Char *) xmalloc((size_t)((cwdlen + (p - cp) + 1) * sizeof(Char)));
  428.     for (p = dp, q = dcwd->di_name; *p++ = *q++;);
  429.     if (cwdlen)
  430.         p[-1] = '/';
  431.     else
  432.         p--;        /* don't add a / after root */
  433.     for (q = cp; *p++ = *q++;);
  434.     xfree((ptr_t) cp);
  435.     cp = dp;
  436.     dp += cwdlen;
  437.     }
  438.     else
  439.     dp = cp;
  440.  
  441.     cp = dcanon(cp, dp);
  442.     return cp;
  443. }
  444.  
  445. /*
  446.  * dfollow - change to arg directory; fall back on cdpath if not valid
  447.  */
  448. static Char *
  449. dfollow(cp)
  450.     register Char *cp;
  451. {
  452.     register Char *dp;
  453.     struct varent *c;
  454.     char    ebuf[MAXPATHLEN];
  455.     int serrno;
  456.  
  457.     cp = globone(cp, G_ERROR);
  458. #ifdef apollo
  459.     if (Strchr(cp, '`')) {
  460.     char *dptr, *ptr;
  461.     if (chdir(dptr = short2str(cp)) < 0) 
  462.         stderror(ERR_SYSTEM, dptr, strerror(errno));
  463.     else if ((ptr = getwd(ebuf)) && *ptr != '\0') {
  464.         xfree((ptr_t) cp);
  465.         cp = Strsave(str2short(ptr));
  466.         return dgoto(cp);
  467.     }
  468.     else 
  469.         stderror(ERR_SYSTEM, dptr, ebuf);
  470.     }
  471. #endif
  472.         
  473.     /*
  474.      * if we are ignoring symlinks, try to fix relatives now.
  475.      */
  476.     dp = dnormalize(cp);
  477.     if (chdir(short2str(dp)) >= 0) {
  478.     xfree((ptr_t) cp);
  479.     return dgoto(dp);
  480.     }
  481.     else {
  482.     xfree((ptr_t) dp);
  483.     if (chdir(short2str(cp)) >= 0) 
  484.         return dgoto(cp);
  485.     serrno = errno;
  486.     }
  487.  
  488. #ifdef __MINT__
  489.     if (!is_abspath(cp) && !prefix(STRdotsl, cp) &&
  490.         !prefix(STRdotdotsl, cp) && (c = adrof(STRcdpath))) {
  491. #else
  492.     if (cp[0] != '/' && !prefix(STRdotsl, cp) && !prefix(STRdotdotsl, cp)
  493.     && (c = adrof(STRcdpath))) {
  494. #endif
  495.     Char  **cdp;
  496.     register Char *p;
  497.     Char    buf[MAXPATHLEN];
  498.  
  499.     for (cdp = c->vec; *cdp; cdp++) {
  500.         for (dp = buf, p = *cdp; *dp++ = *p++;);
  501.         dp[-1] = '/';
  502.         for (p = cp; *dp++ = *p++;);
  503.         if (chdir(short2str(buf)) >= 0) {
  504.         printd = 1;
  505.         xfree((ptr_t) cp);
  506.         cp = Strsave(buf);
  507.         return dgoto(cp);
  508.         }
  509.     }
  510.     }
  511.     dp = value(cp);
  512. #ifdef __MINT__
  513.     if ((is_abspath(dp) || dp[0] == '.') && chdir(short2str(dp)) >= 0) {
  514. #else
  515.     if ((dp[0] == '/' || dp[0] == '.') && chdir(short2str(dp)) >= 0) {
  516. #endif
  517.     xfree((ptr_t) cp);
  518.     cp = Strsave(dp);
  519.     printd = 1;
  520.     return dgoto(cp);
  521.     }
  522.     (void) strcpy(ebuf, short2str(cp));
  523.     xfree((ptr_t) cp);
  524. #ifdef CSHDIRS
  525.     /*
  526.      * on login source of ~/.cshdirs, errors are eaten. the dir stack is all
  527.      * directories we could get to.
  528.      */
  529.     if (!bequiet)
  530.     stderror(ERR_SYSTEM, ebuf, strerror(serrno));
  531.     else
  532.     return (NOSTR);
  533. #else
  534.     stderror(ERR_SYSTEM, ebuf, strerror(serrno));
  535. #endif
  536.     /* NOTREACHED */
  537.     return (NOSTR);
  538. }
  539.  
  540.  
  541. /*
  542.  * dopushd - push new directory onto directory stack.
  543.  *    with no arguments exchange top and second.
  544.  *    with numeric argument (+n) bring it to top.
  545.  */
  546. /*ARGSUSED*/
  547. void
  548. dopushd(v, c)
  549.     Char  **v;
  550.     struct command *c;
  551. {
  552.     register struct directory *dp;
  553.     register Char *cp;
  554.  
  555.     skipargs(&v, " [<dir>|+<n>]");
  556.     printd = 1;
  557.     if (*v == NOSTR) {
  558.     if (adrof(STRpushdtohome)) {
  559.         if ((cp = value(STRhome)) == NOSTR || *cp == 0)
  560.         stderror(ERR_NAME | ERR_NOHOMEDIR);
  561.         if (chdir(short2str(cp)) < 0)
  562.         stderror(ERR_NAME | ERR_CANTCHANGE);
  563.         cp = Strsave(cp);    /* hmmm... PWP */
  564.         cp = dfollow(cp);
  565.         dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
  566.         dp->di_name = cp;
  567.         dp->di_count = 0;
  568.         dp->di_prev = dcwd;
  569.         dp->di_next = dcwd->di_next;
  570.         dcwd->di_next = dp;
  571.         dp->di_next->di_prev = dp;
  572.     }
  573.     else {
  574.         char   *tmp;
  575.  
  576.         if ((dp = dcwd->di_prev) == &dhead)
  577.         dp = dhead.di_prev;
  578.         if (dp == dcwd)
  579.         stderror(ERR_NAME | ERR_NODIR);
  580.         if (chdir(tmp = short2str(dp->di_name)) < 0)
  581.         stderror(ERR_SYSTEM, tmp, strerror(errno));
  582.         dp->di_prev->di_next = dp->di_next;
  583.         dp->di_next->di_prev = dp->di_prev;
  584.         dp->di_next = dcwd->di_next;
  585.         dp->di_prev = dcwd;
  586.         dcwd->di_next->di_prev = dp;
  587.         dcwd->di_next = dp;
  588.     }
  589.     }
  590.     else if (v[1] != NOSTR) {
  591.     stderror(ERR_NAME | ERR_TOOMANY);
  592.     /* NOTREACHED */
  593.     return;
  594.     }
  595.     else if (dp = dfind(*v)) {
  596.     char   *tmp;
  597.  
  598.     if (chdir(tmp = short2str(dp->di_name)) < 0)
  599.         stderror(ERR_SYSTEM, tmp, strerror(errno));
  600.     /*
  601.      * kfk - 10 Feb 1984 - added new "extraction style" pushd +n
  602.      */
  603.     if (adrof(STRdextract))
  604.         dextract(dp);
  605.     }
  606.     else {
  607.     register Char *ccp;
  608.  
  609.     ccp = dfollow(*v);
  610.     dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
  611.     dp->di_name = ccp;
  612.     dp->di_count = 0;
  613.     dp->di_prev = dcwd;
  614.     dp->di_next = dcwd->di_next;
  615.     dcwd->di_next = dp;
  616.     dp->di_next->di_prev = dp;
  617.     }
  618.     dnewcwd(dp);
  619. }
  620.  
  621. /*
  622.  * dfind - find a directory if specified by numeric (+n) argument
  623.  */
  624. static struct directory *
  625. dfind(cp)
  626.     register Char *cp;
  627. {
  628.     register struct directory *dp;
  629.     register int i;
  630.     register Char *ep;
  631.  
  632.     if (*cp++ != '+')
  633.     return (0);
  634.     for (ep = cp; Isdigit(*ep); ep++)
  635.     continue;
  636.     if (*ep)
  637.     return (0);
  638.     i = getn(cp);
  639.     if (i <= 0)
  640.     return (0);
  641.     for (dp = dcwd; i != 0; i--) {
  642.     if ((dp = dp->di_prev) == &dhead)
  643.         dp = dp->di_prev;
  644.     if (dp == dcwd)
  645.         stderror(ERR_NAME | ERR_DEEP);
  646.     }
  647.     return (dp);
  648. }
  649.  
  650. /*
  651.  * dopopd - pop a directory out of the directory stack
  652.  *    with a numeric argument just discard it.
  653.  */
  654. /*ARGSUSED*/
  655. void
  656. dopopd(v, c)
  657.     Char  **v;
  658.     struct command *c;
  659. {
  660.     register struct directory *dp, *p = NULL;
  661.  
  662.     skipargs(&v, " [+<n>]");
  663.     printd = 1;
  664.     if (*v == NOSTR)
  665.     dp = dcwd;
  666.     else if (v[1] != NOSTR) {
  667.     stderror(ERR_NAME | ERR_TOOMANY);
  668.     /* NOTREACHED */
  669.     return;
  670.     }
  671.     else if ((dp = dfind(*v)) == 0)
  672.     stderror(ERR_NAME | ERR_BADDIR);
  673.     if (dp->di_prev == &dhead && dp->di_next == &dhead)
  674.     stderror(ERR_NAME | ERR_EMPTY);
  675.     if (dp == dcwd) {
  676.     char   *tmp;
  677.  
  678.     if ((p = dp->di_prev) == &dhead)
  679.         p = dhead.di_prev;
  680.     if (chdir(tmp = short2str(p->di_name)) < 0)
  681.         stderror(ERR_SYSTEM, tmp, strerror(errno));
  682.     }
  683.     dp->di_prev->di_next = dp->di_next;
  684.     dp->di_next->di_prev = dp->di_prev;
  685.     if (dp == dcwd)
  686.     dnewcwd(p);
  687.     else {
  688.     printdirs();
  689.     }
  690.     dfree(dp);
  691. }
  692.  
  693. /*
  694.  * dfree - free the directory (or keep it if it still has ref count)
  695.  */
  696. void
  697. dfree(dp)
  698.     register struct directory *dp;
  699. {
  700.  
  701.     if (dp->di_count != 0) {
  702.     dp->di_next = dp->di_prev = 0;
  703.     }
  704.     else {
  705.     xfree((char *) dp->di_name);
  706.     xfree((ptr_t) dp);
  707.     }
  708. }
  709.  
  710. /*
  711.  * dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
  712.  *    we are of course assuming that the file system is standardly
  713.  *    constructed (always have ..'s, directories have links)
  714.  */
  715. Char   *
  716. dcanon(cp, p)
  717.     register Char *cp, *p;
  718. {
  719.     register Char *sp;
  720.     register Char *p1, *p2;    /* general purpose */
  721.     bool    slash;
  722. #ifdef apollo
  723.     bool    slashslash;
  724. #endif
  725.  
  726. #ifdef S_IFLNK            /* if we have symlinks */
  727.     Char    link[MAXPATHLEN];
  728.     char    tlink[MAXPATHLEN];
  729.     int     cc;
  730.     Char   *newcp;
  731. #endif                /* S_IFLNK */
  732.  
  733.     /*
  734.      * christos: if the path given does not start with a slash prepend cwd. If
  735.      * cwd does not start with a slash or the result would be too long abort().
  736.      */
  737. #ifdef __MINT__
  738.     if (!is_abspath(cp)) {
  739. #else
  740.     if (*cp != '/') {
  741. #endif
  742.     Char    tmpdir[MAXPATHLEN];
  743.  
  744.     p1 = value(STRcwd);
  745. #ifdef __MINT__
  746.     if (p1 == NULL || !is_abspath(p1))
  747. #else
  748.     if (p1 == NULL || *p1 != '/')
  749. #endif
  750.         abort();
  751.     if (Strlen(p1) + Strlen(cp) + 1 >= MAXPATHLEN)
  752.         abort();
  753.     (void) Strcpy(tmpdir, p1);
  754.     (void) Strcat(tmpdir, STRslash);
  755.     (void) Strcat(tmpdir, cp);
  756.     xfree((ptr_t) cp);
  757.     cp = p = Strsave(tmpdir);
  758.     }
  759.  
  760. #ifdef COMMENT
  761.     if (*cp != '/')
  762.     abort();
  763. #endif
  764.  
  765. #ifdef apollo
  766.     slashslash = (cp[0] == '/' && cp[1] == '/');
  767. #endif
  768.  
  769.     while (*p) {        /* for each component */
  770.     sp = p;            /* save slash address */
  771. #ifdef __MINT__
  772.     do { ++p;
  773.     } while (is_dirsep(*p));    /* flush extra slashes */
  774. #else
  775.     while (*++p == '/')    /* flush extra slashes */
  776.         ;
  777. #endif
  778.     if (p != ++sp)
  779.         for (p1 = sp, p2 = p; *p1++ = *p2++;);
  780.     p = sp;            /* save start of component */
  781.     slash = 0;
  782.     while (*++p)        /* find next slash or end of path */
  783. #ifdef __MINT__
  784.         if (is_dirsep(*p)) {
  785. #else
  786.         if (*p == '/') {
  787. #endif
  788.         slash = 1;
  789.         *p = 0;
  790.         break;
  791.         }
  792.  
  793. #ifdef apollo
  794.     if (&cp[1] == sp && sp[0] == '.' && sp[1] == '.' && sp[2] == '\0')
  795.         slashslash = 1;
  796. #endif
  797.     if (*sp == '\0')    /* if component is null */
  798.         if (--sp == cp)    /* if path is one char (i.e. /) */ 
  799.         break;
  800.         else
  801.         *sp = '\0';
  802.     else if (sp[0] == '.' && sp[1] == 0) {
  803.         if (slash) {
  804.         for (p1 = sp, p2 = p + 1; *p1++ = *p2++;);
  805.         p = --sp;
  806.         }
  807.         else if (--sp != cp)
  808.         *sp = '\0';
  809.     }
  810.     else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
  811.         /*
  812.          * We have something like "yyy/xxx/..", where "yyy" can be null or
  813.          * a path starting at /, and "xxx" is a single component. Before
  814.          * compressing "xxx/..", we want to expand "yyy/xxx", if it is a
  815.          * symbolic link.
  816.          */
  817.         *--sp = 0;        /* form the pathname for readlink */
  818. #ifdef S_IFLNK            /* if we have symlinks */
  819.         if (sp != cp && !adrof(STRignore_symlinks) &&
  820.         (cc = readlink(short2str(cp), tlink,
  821.                    sizeof tlink)) >= 0) {
  822.         (void) Strcpy(link, str2short(tlink));
  823.         link[cc] = '\0';
  824.  
  825.         if (slash)
  826.             *p = '/';
  827.         /*
  828.          * Point p to the '/' in "/..", and restore the '/'.
  829.          */
  830.         *(p = sp) = '/';
  831.         /*
  832.          * find length of p
  833.          */
  834.         for (p1 = p; *p1++;);
  835. #ifdef __MINT__
  836.         if (!is_abspath(link)) {
  837. #else
  838.         if (*link != '/') {
  839. #endif
  840.             /*
  841.              * Relative path, expand it between the "yyy/" and the
  842.              * "/..". First, back sp up to the character past "yyy/".
  843.              */
  844. #ifdef __MINT__
  845.             do { --sp; } while (!is_dirsep(*sp)) ;
  846. #else
  847.             while (*--sp != '/');
  848. #endif
  849.             sp++;
  850.             *sp = 0;
  851.             /*
  852.              * New length is "yyy/" + link + "/.." and rest
  853.              */
  854.             p1 = newcp = (Char *) xmalloc((size_t)
  855.                         (((sp - cp) + cc + (p1 - p)) *
  856.                          sizeof(Char)));
  857.             /*
  858.              * Copy new path into newcp
  859.              */
  860.             for (p2 = cp; *p1++ = *p2++;);
  861.             for (p1--, p2 = link; *p1++ = *p2++;);
  862.             for (p1--, p2 = p; *p1++ = *p2++;);
  863.             /*
  864.              * Restart canonicalization at expanded "/xxx".
  865.              */
  866.             p = sp - cp - 1 + newcp;
  867.         }
  868.         else {
  869.             /*
  870.              * New length is link + "/.." and rest
  871.              */
  872.             p1 = newcp = (Char *) xmalloc((size_t)
  873.                         ((cc + (p1 - p)) * sizeof(Char)));
  874.             /*
  875.              * Copy new path into newcp
  876.              */
  877.             for (p2 = link; *p1++ = *p2++;);
  878.             for (p1--, p2 = p; *p1++ = *p2++;);
  879.             /*
  880.              * Restart canonicalization at beginning
  881.              */
  882.             p = newcp;
  883.         }
  884.         xfree((ptr_t) cp);
  885.         cp = newcp;
  886.         continue;    /* canonicalize the link */
  887.         }
  888. #endif                /* S_IFLNK */
  889.         *sp = '/';
  890.         if (sp != cp)
  891. #ifdef __MINT__
  892.         do { --sp; } while (!is_dirsep(*sp));
  893. #else
  894.         while (*--sp != '/');
  895. #endif
  896.         if (slash) {
  897.         for (p1 = sp + 1, p2 = p + 1; *p1++ = *p2++;);
  898.         p = sp;
  899.         }
  900.         else if (cp == sp)
  901.         *++sp = '\0';
  902.         else
  903.         *sp = '\0';
  904.     }
  905.     else {            /* normal dir name (not . or .. or nothing) */
  906.  
  907. #ifdef S_IFLNK            /* if we have symlinks */
  908.         if (sp != cp && adrof(STRchase_symlinks) &&
  909.         !adrof(STRignore_symlinks) &&
  910.         (cc = readlink(short2str(cp), tlink,
  911.                    sizeof tlink)) >= 0) {
  912.         (void) Strcpy(link, str2short(tlink));
  913.         link[cc] = '\0';
  914.  
  915.         /*
  916.          * restore the '/'.
  917.          */
  918.         if (slash)
  919.             *p = '/';
  920.  
  921.         /*
  922.          * point sp to p (rather than backing up).
  923.          */
  924.         sp = p;
  925.  
  926.         /*
  927.          * find length of p
  928.          */
  929.         for (p1 = p; *p1++;);
  930. #ifdef __MINT__
  931.         if (!is_abspath(link)) {
  932. #else
  933.         if (*link != '/') {
  934. #endif
  935.             /*
  936.              * Relative path, expand it between the "yyy/" and the
  937.              * remainder. First, back sp up to the character past
  938.              * "yyy/".
  939.              */
  940. #ifdef __MINT__
  941.             do { --sp; } while (!is_dirsep(*sp));
  942. #else
  943.             while (*--sp != '/');
  944. #endif
  945.             sp++;
  946.             *sp = 0;
  947.             /*
  948.              * New length is "yyy/" + link + "/.." and rest
  949.              */
  950.             p1 = newcp = (Char *) xmalloc((size_t)
  951.                           (((sp - cp) + cc + (p1 - p))
  952.                            * sizeof(Char)));
  953.             /*
  954.              * Copy new path into newcp
  955.              */
  956.             for (p2 = cp; *p1++ = *p2++;);
  957.             for (p1--, p2 = link; *p1++ = *p2++;);
  958.             for (p1--, p2 = p; *p1++ = *p2++;);
  959.             /*
  960.              * Restart canonicalization at expanded "/xxx".
  961.              */
  962.             p = sp - cp - 1 + newcp;
  963.         }
  964.         else {
  965.             /*
  966.              * New length is link + the rest
  967.              */
  968.             p1 = newcp = (Char *) xmalloc((size_t)
  969.                         ((cc + (p1 - p)) * sizeof(Char)));
  970.             /*
  971.              * Copy new path into newcp
  972.              */
  973.             for (p2 = link; *p1++ = *p2++;);
  974.             for (p1--, p2 = p; *p1++ = *p2++;);
  975.             /*
  976.              * Restart canonicalization at beginning
  977.              */
  978.             p = newcp;
  979.         }
  980.         xfree((ptr_t) cp);
  981.         cp = newcp;
  982.         continue;    /* canonicalize the link */
  983.         }
  984. #endif                /* S_IFLNK */
  985.         if (slash)
  986.         *p = '/';
  987.     }
  988.     }
  989.  
  990.     /*
  991.      * fix home...
  992.      */
  993. #ifdef S_IFLNK
  994.     p1 = value(STRhome);
  995.     cc = Strlen(p1);
  996.     /*
  997.      * See if we're not in a subdir of STRhome
  998.      */
  999. #ifdef __MINT__
  1000.     if (p1 && is_abspath(p1) &&
  1001.     (Strncmp(p1, cp, cc) != 0 || (!is_dirsep(cp[cc]) && cp[cc] != '\0'))) {
  1002. #else
  1003.     if (p1 && *p1 == '/' &&
  1004.     (Strncmp(p1, cp, cc) != 0 || (cp[cc] != '/' && cp[cc] != '\0'))) {
  1005. #endif
  1006.     static ino_t home_ino = -1;
  1007.     static dev_t home_dev = -1;
  1008.     static Char *home_ptr = NULL;
  1009.     struct stat statbuf;
  1010.  
  1011.     /*
  1012.      * Get dev and ino of STRhome
  1013.      */
  1014.     if (home_ptr != p1 &&
  1015.         stat(short2str(p1), &statbuf) != -1) {
  1016.         home_dev = statbuf.st_dev;
  1017.         home_ino = statbuf.st_ino;
  1018.         home_ptr = p1;
  1019.     }
  1020.     /*
  1021.      * Start comparing dev & ino backwards
  1022.      */
  1023.     p2 = Strcpy(link, cp);
  1024.     for (sp = NULL; *p2 && stat(short2str(p2), &statbuf) != -1;) {
  1025.         if (statbuf.st_dev == home_dev &&
  1026.         statbuf.st_ino == home_ino) {
  1027.         sp = (Char *) - 1;
  1028.         break;
  1029.         }
  1030. #ifdef __MINT__
  1031.         sp = Lastslash(p2);
  1032.         if (sp == 0 && p2[1] == ':') sp = p2;
  1033.         if (sp) *sp = '\0';
  1034. #else
  1035.         if (sp = Strrchr(p2, '/'))
  1036.         *sp = '\0';
  1037. #endif
  1038.     }
  1039.     /*
  1040.      * See if we found it
  1041.      */
  1042.     if (*p2 && sp == (Char *) -1) {
  1043.         /*
  1044.          * Use STRhome to make '~' work
  1045.          */
  1046.         newcp = Strspl(p1, cp + Strlen(p2));
  1047.         xfree((ptr_t) cp);
  1048.         cp = newcp;
  1049.     }
  1050.     }
  1051. #endif                /* S_IFLNK */
  1052.  
  1053. #ifdef apollo
  1054.     if (slashslash) {
  1055.     if (cp[1] != '/') {
  1056.         p = (Char *) xmalloc((size_t) (Strlen(cp) + 2) * sizeof(Char));
  1057.         *p = '/';
  1058.         (void) Strcpy(&p[1], cp);
  1059.         xfree((ptr_t) cp);
  1060.         cp = p;
  1061.     }
  1062.     }
  1063.     if (cp[1] == '/' && cp[2] == '/') 
  1064.     (void) Strcpy(&cp[1], &cp[2]);
  1065. #endif
  1066.     return cp;
  1067. }
  1068.  
  1069.  
  1070. /*
  1071.  * dnewcwd - make a new directory in the loop the current one
  1072.  */
  1073. static void
  1074. dnewcwd(dp)
  1075.     register struct directory *dp;
  1076. {
  1077.     dcwd = dp;
  1078.     dset(dcwd->di_name);
  1079.     if (printd && !(adrof(STRpushdsilent))    /* PWP: pushdsilent */
  1080. #ifdef CSHDIRS
  1081.     && !bequiet        /* be quite while restoring stack -strike */
  1082. #endif
  1083.     )
  1084.     printdirs();
  1085.     cwd_cmd();            /* PWP: run the defined cwd command */
  1086. }
  1087.  
  1088. /*
  1089.  * getstakd - added by kfk 17 Jan 1984
  1090.  * Support routine for the stack hack.  Finds nth directory in
  1091.  * the directory stack, or finds last directory in stack.
  1092.  */
  1093. int
  1094. getstakd(s, cnt)
  1095.     Char   *s;
  1096.     int     cnt;
  1097. {
  1098.     struct directory *dp;
  1099.  
  1100.     dp = dcwd;
  1101.     if (cnt < 0) {        /* < 0 ==> last dir requested. */
  1102.     dp = dp->di_next;
  1103.     if (dp == &dhead)
  1104.         dp = dp->di_next;
  1105.     }
  1106.     else {
  1107.     while (cnt-- > 0) {
  1108.         dp = dp->di_prev;
  1109.         if (dp == &dhead)
  1110.         dp = dp->di_prev;
  1111.         if (dp == dcwd)
  1112.         return (0);
  1113.     }
  1114.     }
  1115.     (void) Strcpy(s, dp->di_name);
  1116.     return (1);
  1117. }
  1118.  
  1119. /*
  1120.  * Karl Kleinpaste - 10 Feb 1984
  1121.  * Added dextract(), which is used in pushd +n.
  1122.  * Instead of just rotating the entire stack around, dextract()
  1123.  * lets the user have the nth dir extracted from its current
  1124.  * position, and pushes it onto the top.
  1125.  */
  1126. void
  1127. dextract(dp)
  1128.     struct directory *dp;
  1129. {
  1130.     if (dp == dcwd)
  1131.     return;
  1132.     dp->di_next->di_prev = dp->di_prev;
  1133.     dp->di_prev->di_next = dp->di_next;
  1134.     dp->di_next = dcwd->di_next;
  1135.     dp->di_prev = dcwd;
  1136.     dp->di_next->di_prev = dp;
  1137.     dcwd->di_next = dp;
  1138. }
  1139.  
  1140. #ifdef CSHDIRS
  1141. /*
  1142.  * create a file called ~/.cshdirs which has a sequence
  1143.  * of pushd commands which will restore the dir stack to
  1144.  * its state before exit/logout. remember that the order
  1145.  * is reversed in the file because we are pushing.
  1146.  * -strike
  1147.  */
  1148. void
  1149. recdirs()
  1150. {
  1151.     int     fp, ftmp, oldidfds;
  1152.     int     cdflag = 0;
  1153.     extern int fast;
  1154.     Char    buf[BUFSIZ];
  1155.  
  1156.     if (!fast) {
  1157.     if (!adrof(STRsavedirs))/* does it exist */
  1158.         return;
  1159.     (void) Strcpy(buf, value(STRhome));
  1160.     (void) Strcat(buf, STRsldtdirs);
  1161.     if ((fp = creat(short2str(buf), 0666)) == -1)
  1162.         return;
  1163.     oldidfds = didfds;
  1164.     didfds = 0;
  1165.     ftmp = SHOUT;
  1166.     SHOUT = fp;
  1167.     {
  1168.         extern struct directory dhead;
  1169.         extern struct directory *dcwd;
  1170.         struct directory *dp = dcwd->di_next;
  1171.  
  1172.         do {
  1173.         if (dp == &dhead)
  1174.             continue;
  1175.         if (cdflag == 0)
  1176.             cdflag++, xprintf("cd %s\n",
  1177.                       short2str(dp->di_name));
  1178.         else
  1179.             xprintf("pushd %s\n",
  1180.                 short2str(dp->di_name));
  1181.         } while ((dp = dp->di_next) != dcwd->di_next);
  1182.     }
  1183.     xprintf("dirs\n");    /* show the dir stack */
  1184.  
  1185.     (void) close(fp);
  1186.     SHOUT = ftmp;
  1187.     didfds = oldidfds;
  1188.     }
  1189. }
  1190.  
  1191. #endif
  1192.